package com.ce.server.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ce.server.common.AdminVo;
import com.ce.server.common.RespBean;
import com.ce.server.common.RespPageBean;
import com.ce.server.config.JwtTokenUtil;
import com.ce.server.mapper.*;
import com.ce.server.pojo.*;
import com.ce.server.service.IAdminService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ce.server.service.IOperlogService;
import com.ce.server.util.AdminUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 郑爽
 * @since 2021-11-14
 */
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements IAdminService {

  @Value("${type.admin}")
  private String admin_type;
  @Value("${type.student}")
  private String student_type;
  @Value("${jwt.tokenHead}")
  private String tokenHead;
  @Autowired
  private RedisTemplate redisTemplate;

  @Autowired
  private UserDetailsService userDetailsService;
  @Autowired
  private PasswordEncoder passwordEncoder;
  @Autowired
  JwtTokenUtil jwtTokenUtil;

  @Autowired
  private AdminMapper adminMapper;
  @Autowired
  private StudentMapper studentMapper;
  @Autowired
  private AdminRoleMapper adminRoleMapper;
  @Autowired
  private IOperlogService operlogService;
  @Autowired
  private WorkingMapper workingMapper;


  /**
   * 登录之后返回token
   *
   * @param account_no
   * @param password
   * @param request
   * @return
   */
  @Override
  public RespBean login(String account_no, String password, String code, HttpServletRequest request) {
    String captcha = (String) request.getSession().getAttribute("captcha");
    if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(code)) {
      return RespBean.error("验证码错误！");
    }

    UserDetails userDetails = userDetailsService.loadUserByUsername(account_no);
    if (userDetails == null || !passwordEncoder.matches(password, userDetails.getPassword())) {
      return RespBean.error("用户名或密码不正确");
    }
    if (!userDetails.isEnabled()) {
      return RespBean.error("账号被禁用请联系管理员！");
    }


    // 更新当前系统用户对象
    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);

    // 生成token并返回给前端
    String token = jwtTokenUtil.generateToken(userDetails);
    Map<String, String> tokenMap = new HashMap<>();
    tokenMap.put("token", token);
    tokenMap.put("tokenHead", tokenHead);
    return RespBean.success("登录成功", tokenMap);
  }

  /**
   * 根据用户名获取用户
   *
   * @param wno
   * @return
   */
  @Override
  public Admin getAdminByWno(String wno) {
    List<Map<String, Object>> maps = workingMapper.selectMaps(new QueryWrapper<Working>().select("max(sortDays)"));
    Date newDate = (Date) maps.get(0).get("max(sortDays)");
    Working working = workingMapper.selectOne(new LambdaQueryWrapper<Working>().eq(Working::getSortDays, newDate).eq(Working::getWno, wno));
    Admin admin = adminMapper.selectOne(new LambdaQueryWrapper<Admin>().eq(Admin::getWno, wno).eq(Admin::isEnabled, true));
    admin.setDoorway(working.getAddress());
    return admin;
  }

  /**
   * 根据用户id查询所拥有的角色
   *
   * @param adminId
   * @return
   */
  @Override
  public List<Role> getRoles(String no) {
    return adminMapper.getRolesWithId(no);

  }

  /**
   * 修改用户信息
   *
   * @param admin
   * @return
   */
  @Override
  public Boolean updateAccountInfo(Admin admin) {

    return adminMapper.updateAccountInfo(admin) > 0 ? true : false;
  }

  /**
   * 分页查询操作员
   *
   * @param currentPage
   * @param size
   * @param admin
   * @return
   */
  @Override
  public RespPageBean getAdminsByPage(Integer currentPage, Integer size, Admin admin) {
    Page<AdminVo> page = new Page<>(currentPage, size);
    IPage<AdminVo> admins = adminMapper.getAdminsByPage(page, admin, AdminUtil.getCurrentAdmin().getUsername());

    RespPageBean respPageBean = new RespPageBean(admins.getTotal(), admins.getRecords());
    return respPageBean;
  }

  /**
   * 添加员工
   *
   * @param admin
   * @return
   */
  @Override
  public RespBean addAdmin(Admin admin) {
    admin.setWno("adm_" + admin.getWno());
    // 新员工默认密码为123456
    String encode = new BCryptPasswordEncoder().encode("123456");
    admin.setPassword(encode);
    if (adminMapper.insert(admin) > 0) {
      Admin currentAdmin = (Admin) AdminUtil.getCurrentAdmin();
      operlogService.save(new Operlog().setWno(currentAdmin.getWno())
              .setWname(currentAdmin.getWname())
              .setOper("修改了值班记录").setOpertime(LocalDateTime.now()));
      return RespBean.success("添加成功！");
    }
    return RespBean.error("添加失败！");
  }

  /**
   * 根据工号删除操作员
   *
   * @param wno
   * @return
   */
  @Override
  public Integer delAdminByWno(String wno) {

    return adminMapper.delAdminByWno(wno);
  }

  /**
   * 更新当前操作员密码
   *
   * @param no
   * @param oldPass
   * @param newPass
   * @return
   */
  @Override
  public RespBean updateCurrentAdmPass(String no, String oldPass, String newPass) {

    if (StringUtils.startsWithIgnoreCase(no, admin_type)) {
      Admin admin = adminMapper.selectOne(new LambdaQueryWrapper<Admin>().eq(Admin::getWno, no));
      if (passwordEncoder.matches(oldPass, admin.getPassword())) {
        if (adminMapper.updateAccountInfo(admin.setPassword(passwordEncoder.encode(newPass))) > 0) {
          return RespBean.success("密码更新成功！");
        }
      } else {
        return RespBean.success("原密码输入错误");
      }
    } else {
      Student student = studentMapper.selectOne(new LambdaQueryWrapper<Student>().eq(Student::getSno, no));
      if (passwordEncoder.matches(oldPass, student.getPassword())) {
        student.setPass(passwordEncoder.encode(newPass));
        if (studentMapper.update(student, new LambdaQueryWrapper<Student>().eq(Student::getSno, no)) > 0) {
          return RespBean.success("密码更新成功！");
        }
      } else {
        return RespBean.error("密码更新失败!");
      }
    }
    return RespBean.error("出现异常，请向管理员反馈！");
  }

  /**
   * 更新操作员角色
   *
   * @param adminWno
   * @param rids
   * @return
   */
  @Override
  @Transactional
  public RespBean updateAdminRole(String adminWno, Integer[] rids) {
    adminRoleMapper.delete(new LambdaUpdateWrapper<AdminRole>().eq(AdminRole::getNo, adminWno));
    if (adminRoleMapper.insertRoles(adminWno, rids) == rids.length) {
      redisTemplate.delete("menu_" + adminWno);
      return RespBean.success("更新操作员角色成功！");
    } else {
      return RespBean.error("更新操作员角色失败！");
    }
  }

  /**
   * 获取操作员最大工号
   *
   * @return
   */
  @Override
  public RespBean getAdminMaxId() {
    List<Map<String, Object>> list_mid = adminMapper.selectMaps(new QueryWrapper<Admin>().select("max(wno)"));
    String maxId = (String) list_mid.get(0).get("max(wno)");
    if (maxId.substring(admin_type.length()) != null) {
      return RespBean.success("成功获取到当前最大工号", maxId.substring(admin_type.length()));
    }
    return RespBean.error("获取当前最大工号失败！");
  }

  /**
   * 获取所有校职工信息
   *
   * @return
   */
  @Override
  public List<AdminVo> getAllRecords() {
    Integer recordNum = adminMapper.selectCount(null);
    Page<AdminVo> adminPage = new Page<>(1, recordNum);
    IPage adminsByPage = adminMapper.getAdminsByPage(adminPage, new Admin(), null);
    return adminsByPage.getRecords();
  }


}
